import Component from "../Component.js";
import Type from "../../experience/db/Type.js";
import Socket from "../../experience/utils/Socket.js";
import {_delay, _timeout} from "../../experience/utils/F7.js";

const Feature = ol.Feature;
const Point = ol.geom.Point;
const Text = ol.style.Text;
const Fill = ol.style.Fill;
const Stroke = ol.style.Stroke;
const Style = ol.style.Style;
const Icon = ol.style.Icon;
const LineString = ol.geom.LineString;
const Overlay = ol.Overlay;


export default class Vehicle extends Component{
    constructor() {
        super();

        this.vehicles = null;
        this.datas = new Map();
        this.THRESHOLD = 0.000001;
        this.vehicleId = this.utils.getLocalStorage("vehicleId");

        // 比例尺锁和车辆移动锁
        this.zoomlocked = true;
        this.lockedUnlocked = true;

        // 轨迹回放相关
        this.playbacks = [];
        this.playbackIndex = 0;
        this.playbackLocked = false;
        this.playbacklength = 100;
        this.playbacktimer = null;

        // 车辆被选中相关
        this.selectedId = null;
        this.selectedTimer = null;

        // 车速补偿相关
        this.statistics = [];
        this.selfinfo = null;

        this.busOtherSrc = "../../assets/images/vehicle/bus-other.png";
        this.tonOtherSrc = "../../assets/images/vehicle/8-ton-other.png";
        this.busSelfSrc = "../../assets/images/vehicle/bus-self.png";
        this.tonSelfSrc = "../../assets/images/vehicle/8-ton-self.png";
        this.tonSelfSvg = "../../assets/images/vehicle/bus-self.svg";

        // 设置Vehicle弹出对话框
        const container = document.getElementById("ol-vehicle-popup");
        const closer = document.getElementById("ol-vehicle-closer");
        if (container !== null && closer !== null) {
            const self = this;
            closer.onclick = function () {
                self.overlay.setPosition(undefined);
                clearInterval(self.selectedTimer);
                self.emitter.emit("cancel-selected");
                self.selectedId = null;
                closer.blur();
                return false;
            };

            this.emitter.on("close-overlay", () => {
                self.overlay.setPosition(undefined);
                clearInterval(self.selectedTimer);
                self.emitter.emit("cancel-selected");
                self.selectedId = null;
                closer.blur();
            });

            this.overlay = new Overlay({ element: container });
            this.drawer.map.addOverlay(this.overlay);
        }

        // 当选择器发出被选中事件
        this.emitter.on("vehicle-selected", () => {
            clearInterval(this.selectedTimer);

            const id = this.emitter.params[0]
            const vehicle = this.datas.get(id);
            this.selectedId = vehicle.carcode;

            this.$$("#ol-vehicle-content-name").html(`车辆: ${vehicle.name}`);
            this.$$("#ol-vehicle-content-person").html(`驾驶员: ${vehicle.driver}`);
            this.$$("#ol-vehicle-content-card").html(`卡号: ${vehicle.carcode}`);

            this.$$("#ol-carcode").html(vehicle.carcode);
            this.$$("#ol-carcode2").html(vehicle.carcode);
            this.$$("#ol-stime").val(moment().subtract(1, 'days').format("YYYY-MM-DD"));
            this.$$("#ol-etime").val(moment().add(1, 'days').format("YYYY-MM-DD"));

            this.selectedTimer = setInterval(() => {
                const vehicle = this.datas.get(id);
                this.info(vehicle);
            }, 1000);
        });

        // 取配置文件信息
        const config = this.algo.getConfig();
        if (config === null) return;

        // 获取轨迹线数据
        this.tracks = new Map();
        this.api.getTracks({ meta_id: config.meta_id, type: "vehicle" }).then(t => {
            for (const data of t.data) {
                this.tracks.set(data.id, data);
            }
        });

        // 获取人员定位分站数据
        this.positions = new Map();
        this.api.getPositions({ meta_id: config.meta_id, type: "vehicle" }).then(p => {
            for (const data of p.data) {
                this.positions.set(data.node_id, data);
            }
        });

        // 获取读卡器信息
        this.readers = new Map();
        debugger
        this.api.getReaders().then(r => {
            for (const data of r.data) {
                this.readers.set(data.readerid, data);
            }
        });
    }

    clear() {
        this.playbackIndex = 0;
        this.playbackLocked = false;
        this.playbacklength = 100;
        this.$$("#person-slider").val(0);
        this.$$("#vp-footer").hide();
        this.$$("#vl-track-back").css("background", "green");
        this.$$("#vl-track-back").html("开始回放");
        clearInterval(this.playbacktimer);
    }

    info(vehicle) {
        const regname = vehicle.regname;
        const diration = vehicle.dir === 0 ? "前" : "后";
        const distance = vehicle.distance;
        this.$$("#ol-inminetime").html(vehicle.inminetime);
        this.$$("#ol-reader").html(`${regname}${diration}${distance}米`);
        this.$$("#ol-speed").html(`${vehicle.speed}Km/h`);
        this.$$("#ol-mileage").html(`${vehicle.mileage}Km`);
        this.$$("#ol-wt").html(`${vehicle.water_temp}℃`);
        this.$$("#ol-ch4").html(`${vehicle.ch4_conc}%`);
        this.$$("#ol-st").html(`${vehicle.surface_temp}℃`);
        this.$$("#ol-et").html(`${vehicle.exhaust_temp}℃`);
        this.$$("#ol-rpm").html(`${vehicle.rpm}rpm`);
        this.$$("#ol-battery").html(`${vehicle.battery}%`);
        this.overlay.setPosition([vehicle.x, vehicle.y]);
    }

    draw() {
        const vehicleId = this.utils.getLocalStorage("vehicleId");
        const config = this.algo.getConfig();
        let vehicle = null
        this.drawer.source(Type.Vehicle).clear();
        this.datas.forEach((item) => {
            if (this.vehicleId === item.carcode || vehicleId === item.carcode) {
                vehicle = item;
                return;
            }
            const feature = new Feature();
            feature.setId(item.id);
            feature.set('type', Type.Vehicle);
            feature.set('carcode', item.carcode);
            const style = new Style({
                image: new Icon({
                    src: item.type === 1 ? this.busOtherSrc : this.tonOtherSrc,
                    scale: config.scale / 8,
                    rotation: -item.angle
                }),
                text: new Text({
                    text: item.name,
                    fill: new Fill({ color: 'white' }),
                    font: `normal 14px "iconfont"`,
                    textAlign: 'center',
                    textBaseline: 'middle',
                    offsetX: 0, offsetY: 30
                })
            });
            feature.setStyle(style);
            item.x = this.algo.normalX(item.x);
            item.y = this.algo.normalY(item.y);
            feature.setGeometry(new Point([item.x, item.y]));
            this.drawer.source(Type.Vehicle).addFeature(feature);
        });

        if (vehicle === null) return;

        const feature = new Feature();
        feature.setId(vehicle.id);
        feature.set('type', Type.Vehicle);
        feature.set('carcode', vehicle.carcode);
        let src;
        if (this.vehicleId === vehicle.carcode) {
            src = vehicle.type === 1 ? this.busSelfSrc : this.tonSelfSrc;
        } else {
            if (vehicleId === vehicle.carcode) {
                src = vehicle.type === 1 ? this.busSelfSrc : this.tonSelfSrc;
            }
        }
        const style = new Style({
            image: new Icon({
                src: src,
                scale: config.scale / 8,
                rotation: -vehicle.angle
            }),
            text: new Text({
                text: vehicle.name,
                fill: new Fill({ color: 'white' }),
                font: `normal 14px "iconfont"`,
                textAlign: 'center',
                textBaseline: 'middle',
                offsetX: 0, offsetY: 30
            })
        });
        feature.setStyle(style);
        vehicle.x = this.algo.normalX(vehicle.x);
        vehicle.y = this.algo.normalY(vehicle.y);
        feature.setGeometry(new Point([vehicle.x, vehicle.y]));
        this.drawer.source(Type.Vehicle).addFeature(feature);
    }

    xy(lspt, lept, len) {
        let x = 0, y = 0;
        if (Math.abs(lspt[0] - lept[0]) < this.THRESHOLD) {
            // 斜率不存在的情况
            x = lspt[0]; y = lspt[1] + len;
            if (lept[1] < lspt[1]) {
                y = lspt[1] - len;
            }
        }
        else {
            // 斜率存在的情况
            const k = this.algo.k(lspt[0], lspt[1], lept[0], lept[1]);

            // 计算出可能在折线段上的两个坐标
            const x1 = lspt[0] + len * Math.cos(k);
            const y1 = lspt[1] + len * Math.sin(k);
            const x2 = lspt[0] + len * Math.cos(k + Math.PI);
            const y2 = lspt[1] + len * Math.sin(k + Math.PI);

            // 满足在折线段范围内的坐标点为正确的坐标
            if (x1 <= Math.max(lspt[0], lept[0]) && x1 >= Math.min(lspt[0], lept[0])) {
                x = x1; y = y1;
            }

            if (x2 <= Math.max(lspt[0], lept[0]) && x2 > Math.min(lspt[0], lept[0])) {
                x = x2; y = y2;
            }
        }
        return { x: x, y: y };
    }

    angle(grid, dir, left=false) {
        let result;
        if (dir === 0) {
            if (left) {
                result =  grid - Math.PI / 2;
            } else {
                result =  grid + Math.PI / 2;
            }
        } else {
            if (left) {
                result =  grid + Math.PI / 2;
            } else {
                result =  grid - Math.PI / 2;
            }
        }
        return result
    }

    statis(reader_id) {
        const readers = [], result = {
            'larger': 0, 'smaller': 0, 'avg': 0, 'distance': 0,
            'left': 0, 'right': 0, 'up': 0, 'down': 0, 'still': 0
        }, length = this.statistics.length;

        // 计算向左、右或者向上、下的数量
        for (let i = 0; i < length - 1; i++) {
            const c = this.statistics[i], n = this.statistics[i+1];
            const d = this.algo.distance(c.x, c.y, n.x, n.y);
            if (d > 1) {
                if (c.x < n.x) result.right += 1;
                if (c.x > n.x) result.left += 1;
                if (c.y < n.y) result.up += 1;
                if (c.y > n.y) result.down += 1;
            }
        }

        // 取出统一分站的信息
        for (let i = 0; i < length; i++) {
            if (this.statistics[i].readerid === reader_id) {
                readers.push(this.statistics[i]);
            }
        }

        // 每两个点进行比较,查看这些点的整体状态
        for (let i = 0; i < readers.length - 1; i++) {
            const c = readers[i], n = readers[i+1];
            const d1 = Math.abs(c['distance']);
            const d2 = Math.abs(n['distance']);

            // 计算逐渐变小或者逐渐变大的数量
            result["distance"] += Math.abs(d1 - d2);
            if (Math.abs(d1 - d2) > this.THRESHOLD) {
                result.smaller = d1 > d2 ? result.smaller + 1 : result.smaller;
                result.larger = d2 > d1 ? result.larger + 1: result.larger;
            }

            // 判断同分站最近连续的几个点是否位置相同
            if (this.algo.distance(c.x, c.y, n.x, n.y) < this.THRESHOLD) {
                if (i > 3) result.still = result.still + 1;
            }
        }

        result.distance = result.distance.toFixed();
        result.avg = (result.distance / readers.length).toFixed(2);
        return result;
    }

    calc(postion, track, dir, d100) {
        const result = { dir: dir, dis: d100, x: 0, y: 0};
        for (let i = 0; i < track.length; i++) {
            const point = track[i];
            const distance = this.algo.distance(postion.x, postion.y, point[0], point[1]);
            if (distance < this.algo.threshold) {
                let tlen = 0;
                if (dir === 0) {
                    if (i === track.length - 1) {
                        result.x = track[i][0]; result.y = track[i][1];
                        const lspt = track[i - 1], lept = track[i];
                        const dx = lept[0] - lspt[0], dy = lept[1] - lspt[1];
                        result.grid = Math.atan2(dy, dx);
                    } else {
                        for (let j = i; j < track.length - 1; j++) {
                            const lspt = track[j], lept = track[j + 1];
                            const llen = this.algo.distance(lspt[0], lspt[1], lept[0], lept[1]);
                            if (tlen + llen > d100) {
                                const slen = d100 - tlen;
                                const p = this.xy(lspt, lept, slen);
                                const dx = lept[0] - lspt[0], dy = lept[1] - lspt[1];
                                result.x = p.x; result.y = p.y; result.grid = Math.atan2(dy, dx);
                                tlen += llen;
                                break;
                            }
                            tlen += llen;
                        }
                        if (tlen < d100) {
                            const index = track.length - 1;
                            const lspt = track[index - 1], lept = track[index];
                            const dx = lept[0] - lspt[0], dy = lept[1] - lspt[1];
                            result.x = lept[0]; result.y = lept[1]; result.grid = Math.atan2(dy, dx);
                        }
                    }
                } else if (i === 0) {
                    result.x = track[0][0]; result.y = track[0][1];
                    const lspt = track[1], lept = track[0];
                    const dx = lept[0] - lspt[0], dy = lept[1] - lspt[1];
                    result.grid = Math.atan2(dy, dx)
                } else {
                    for (let j = i; j > 0; j--) {
                        const lspt = track[j], lept = track[j - 1];
                        const llen = this.algo.distance(lspt[0], lspt[1], lept[0], lept[1]);
                        if (tlen + llen > d100) {
                            const slen = d100 - tlen;
                            const p = this.xy(lspt, lept, slen);
                            const dx = lept[0] - lspt[0], dy = lept[1] - lspt[1];
                            result.x = p.x; result.y = p.y; result.grid = Math.atan2(dy, dx);
                            tlen += llen;
                            break;
                        }
                        tlen += llen;
                    }
                    if (tlen < d100) {
                        const lspt = track[1], lept = track[0];
                        const dx = lept[0] - lspt[0], dy = lept[1] - lspt[1];
                        result.x = lept[0];
                        result.y = lept[1];
                        result.grid = Math.atan2(dy, dx);
                    }
                }
                break;
            }
        }
        return result;
    }

    vehicle(vehicles) {
        for (const vehicle of vehicles) {
            // 1.如果是终端模式
            if (this.vehicleId === vehicle.carcode) {
                // 从端口为8899的Websocket获取的数据
                if (this.selfinfo !== null) {
                    console.log("【Websocket】");
                    console.log("【启动本地车速补偿算法。】");
                    const info = this.selfinfo;
                    if (info.direction !== null) vehicle.dir = parseInt(info.direction);
                    if (info.distance1 !== null) vehicle.yukirin = parseFloat(info.distance1);
                    if (info.speed !== null) vehicle.speed = parseFloat(info.speed);
                    if (info.totalMiles !== null) vehicle.mileage = info.totalMiles;
                    if (info.ch4 !== null) vehicle.ch4_conc = parseInt(info.ch4);
                    if (info.rpm !== null) vehicle.rpm = info.rpm;
                    if (info.battery !== null) vehicle.battery = info.battery;
                    if (info.exhTemp !== null) vehicle.exhaust_temp = info.exhTemp;
                    if (info.engTemp !== null) vehicle.surface_temp = info.engTemp;
                    if (info.coolTemp !== null) vehicle.water_temp = info.coolTemp;

                    // ① 判断分站是否能存在,获取分站、轨迹线
                    if (vehicle.readerid === null) continue;
                    const postion = this.positions.get(parseInt(vehicle.readerid));
                    if (postion === undefined) continue;
                    const track = this.tracks.get(postion.track_id);
                    if (track === undefined) continue;

                    // ② 计算车辆在当前分站的位置
                    if (this.statistics.length === 0) {
                        // 刚启动第一次获取车辆信息
                        const v = this.calc(postion, track.points, vehicle.dir, vehicle.yukirin);
                        vehicle.x = v.x; vehicle.y = v.y; vehicle.grid = v.grid;
                        vehicle.left = false; vehicle.angle = this.angle(v.grid, vehicle.dir);
                    } else {
                        // 计算当前时间与系统更新时间的差值
                        const ct = moment(vehicle.time, 'YYYY-MM-DD HH:mm:ss'), nt = moment();
                        const seconds = Math.floor(nt.diff(ct) / 1000);
                        console.log("|START- 当前时间 =>", nt.format('YYYY-MM-DD HH:mm:ss'), "-START|");
                        console.log("|---- 服务时间 =>", vehicle.time, "--------|");

                        // 计算统计数据
                        const stat = this.statis(vehicle.readerid);

                        // 计算一下和上次的距离
                        const last = this.statistics[this.statistics.length - 1];
                        const d = Math.abs(vehicle.yukirin - last.yukirin).toFixed(2);

                        console.log("时间间隔 =>", seconds, "| 保持次数 =>", stat.still, "| 距离 => ", d);

                        if ((seconds > 2 && seconds < 300) && (stat.still < 6)) {
                            const dv = (vehicle.yukirin + vehicle.speed / 3.6).toFixed(2);
                            const xy = this.calc(postion, track.points, vehicle.dir, dv);
                            console.log("【开启补偿】 => ", dv, "车速 => ", vehicle.speed);

                            // 看是否满足和当前车辆行使同向
                            if ((stat.left > stat.right && xy.x < last.x) ||
                                (stat.left < stat.right && xy.x > last.x)) {
                                vehicle.yukirin = dv;
                            }
                        } else if (vehicle.readerid === last.readerid && d < 1.5) {
                            // 同一分站并且间距很小的情况,则保持和上一条数据一致
                            vehicle.x = last.x; vehicle.y = last.y; vehicle.grid = last.grid;
                            vehicle.left = last.left; vehicle.angle = last.angle;
                            console.log("【位置相同】");
                        }

                        const v = this.calc(postion, track.points, vehicle.dir, vehicle.yukirin);
                        vehicle.x = v.x; vehicle.y = v.y; vehicle.grid = v.grid;
                        vehicle.angle = this.angle(v.grid, vehicle.dir, last.left);
                        vehicle.left = (vehicle.x < last.x);
                    }

                    console.log("|END--------------------------------------END|");
                    console.log("");

                    // ③ 加入最新的车辆记录,保证统计数据列表中只有10条数据
                    this.statistics.push(this.utils.deepcopy(vehicle));
                    if (this.statistics.length > 11) this.statistics.shift();

                    this.$$("#distance").html(`相对位置: ${vehicle.yukirin}米`);
                } else {
                    this.$$("#distance").html(`相对位置: ${vehicle.distance}米`);
                    console.log("【Network】");
                }

                // 需要添加左上的状态信息
                this.$$("#vehicleid").html(`识别卡号: ${vehicle.carcode}`);
                this.$$("#readerid").html(`读卡器: ${vehicle.regname}`);
                this.$$("#direction").html(`相对方向: ${vehicle.dir === 0 ? "前" : "后"}`);
                this.$$("#speed").html(`车辆速度: ${vehicle.speed}Km/h`);

                // 将中心坐标始终指向这辆车
                const x = this.algo.normalX(vehicle.x);
                const y = this.algo.normalY(vehicle.y);
                if (this.zoomlocked) {
                    // 打开车辆追踪模式,第一次要放大地图
                    this.zoomlocked = false;
                    this.drawer.map.getView().setCenter([x, y]);
                    this.drawer.map.getView().setZoom(12);
                } else {
                    this.drawer.map.getView().setCenter([x, y]);
                }
            }

            // 2.如果车辆信息对话框已经打开
            if (this.selectedId === vehicle.carcode) {
                const x = this.algo.normalX(vehicle.x);
                const y = this.algo.normalY(vehicle.y);
                this.overlay.setPosition([x, y]);
            }

            this.datas.set(vehicle.id, vehicle);
        }
    }

    async playback(index = 0) {
        this.toast("注意: 绿色为规定轨迹线、橙色为非规定轨迹线。");

        // 添加移动的车辆
        const car = new Feature(), playbacks = this.playbacks;
        const icon = new Icon({src: this.tonSelfSvg, size: [60, 60]});
        car.setStyle(new Style({image: icon}));
        this.drawer.source(Type.Modify).addFeature(car);

        // 添加轨迹线
        const db = await this.db.index(Type.Track, "type", "vehicle");
        db.forEach(item => {
            item.points.forEach(p => {
                p[0] = this.algo.normalX(p[0]); p[1] = this.algo.normalY(p[1]);
            });

            const feature = new Feature();
            feature.setStyle(new Style({stroke: new Stroke({width: 2, color: 'orange'})}));
            feature.setGeometry(new LineString(item.points));
            this.drawer.source(Type.Modify).addFeature(feature);
        });

        // 如果存在规定轨迹线,则显示出来
        const param = { car_id: playbacks[0].carid, time: playbacks[0].time };
        const data = await this.api.getCarTracks(param);
        data.data.forEach(item => {
            item.coordinates.forEach(p => {
                p[0] = this.algo.normalX(p[0]); p[1] = this.algo.normalY(p[1]);
            });

            const feature = new Feature();
            feature.setStyle(new Style({stroke: new Stroke({width: 6, color: 'green'})}));
            feature.setGeometry(new LineString(item.coordinates));
            this.drawer.source(Type.Modify).addFeature(feature);
        });

        const length = this.playbacks.length;
        let i = index, count = 0, flag = true, x1, y1, x2, y2, k, distance;
        this.playbacktimer = setInterval(async () => {
            // 停止轨迹回放
            if (!this.playbackLocked || i === length - 1) {
                this.playbackIndex = i;
                this.drawer.source(Type.Modify).clear();
                clearInterval(this.playbacktimer);
                return;
            }

            const curr = playbacks[i], next = playbacks[i + 1];
            if (flag) {
                flag = false;

                // 判断当前分站是否存在,如果不存在标记为黄色
                this.$$(`#${curr.id}`).css("background-color", "rgb(255, 255, 0, 0.8)");
                const currPosition = this.positions.get(curr.rid);
                if (currPosition === undefined) { i = i + 1; flag = true; return; }
                this.$$(`#${curr.id}`).css("background-color", "rgb(0, 255, 0, 0.8)");

                // 判断下一个分站是否存在,如果不存在标记为黄色
                this.$$(`#${next.id}`).css("background-color", "rgb(255, 255, 0, 0.8)");
                const nextPosition = this.positions.get(next.rid);
                if (nextPosition === undefined) { i = i + 1; flag = true; return; }
                this.$$(`#${next.id}`).css("background-color", "rgb(0, 255, 0, 0.8)");

                // 计算线段位置、斜率、长度
                x1 = this.algo.normalX(currPosition.x); y1 = this.algo.normalY(currPosition.y);
                x2 = this.algo.normalX(nextPosition.x); y2 = this.algo.normalY(nextPosition.y);
                distance = this.algo.distance(x1, y1, x2, y2); k = this.algo.k(x1, y1, x2, y2);

                const center = [(x1 + x2) / 2, (y1 + y2) / 2];
                this.drawer.map.getView().animate({ center: center });
            }

            // 计算出可能在折线段上的两个坐标
            let x, y, dl = this.playbacklength * count;
            if (dl > distance) {
                car.setGeometry(new Point([x2, y2]));
                flag = true;
                count = 0;
                i = i + 1;
            } else {
                const xd1 = x1 + dl * Math.cos(k), yd1 = y1 + dl * Math.sin(k);
                const xd2 = x1 + dl * Math.cos(k + Math.PI), yd2 = y1 + dl * Math.sin(k + Math.PI);

                // 满足在折线段范围内的坐标点为正确的坐标
                if (xd1 <= Math.max(x1, x2) && xd1 >= Math.min(x1, x2)) { x = xd1; y = yd1; }
                if (xd2 <= Math.max(x1, x2) && xd2 >= Math.min(x1, x2)) { x = xd2; y = yd2; }
                car.setGeometry(new Point([x, y]));
                count = count + 1;
            }
        }, 100);
    }

    template() {
        const self = this;

        function htmls() {
            const vehicleId = self.utils.getLocalStorage("vehicleId");
            if (vehicleId === null || vehicleId === undefined) {
                const route = self.utils.getLocalStorage("route");
                if (!route) {
                    // 在route模式下,因为要嵌入到打车的框架下,这些按钮就不显示了
                    const vehicle_id_div = `
                        <div id="vp-header">
                            <button class="button button-fill color-primary" id="vehicle-locked">
                                <span class="icon iconfont">&#xe600;</span>
                                车辆锁定
                            </button>
                            <button class="button button-fill color-primary" id="vehicle-unlocked">
                                <span class="icon iconfont">&#xe601;</span>
                                取消锁定
                            </button>
                            <button class="button button-fill color-primary" id="vehicle-positions">
                                <span class="icon iconfont">&#xe651;</span>
                                选择分站
                            </button>
                            <button class="button button-fill color-primary" id="measure">
                                <span class="icon iconfont">&#xe634;</span>
                                测量距离
                            </button>
                        </div>
                    `;
                    self.$$("#article").append(vehicle_id_div);
                }
                self.$$("#vehicle-locked-unlocked").hide();
            } else {
                const vehicle_id_div = `
                    <div id="vehicle">
                        <div class="vehicle-item"><span id="vehicleid"></span></div>
                        <div class="vehicle-item"><span id="readerid"></span></div>
                        <div class="vehicle-item"><span id="direction"></span></div>
                        <div class="vehicle-item"><span id="distance"></span></div>
                        <div class="vehicle-item"><span id="speed"></span></div>
                    </div>
                `;
                self.$$("#article").append(vehicle_id_div);
                self.$$("#vehicle-locked-unlocked").show();
            }

            const track_div = `
                <div class="page" id="pannel" style="top: 60px; width: 20vw; height: 90vh;">
                    <div class="page-title">
                        <span id="vl-title">轨迹回放</span>
                        <div>
                            <div class="page-cheked">
                                <button class="button button-fill" style="background: green; cursor: pointer" 
                                    id="vl-track-back">
                                    开始回放
                                </button>
                                <i class="iconfont" style="font-size: 22px; cursor: pointer;" id="pannel-close">&#xe6ba;</i>
                            </div>
                        </div>
                    </div>
                    <div class="page-content"></div>
                </div>
            `;
            self.$$("#article").append(track_div);
            self.$$("#pannel").hide();


            const vp_footer_div = `
                <div id="vp-footer">
                    <input type="range" name="slider" min="0" max="20" step="1" value="0" id="person-slider"/>
                </div>
            `;
            self.$$("#article").append(vp_footer_div);
            self.$$("#vp-footer").hide();
        }

        function popup() {
            const div = `
                <div id="ol-vehicle-popup" class="ol-popup">
                    <a href="#" id="ol-vehicle-closer" class="ol-popup-closer"></a>
                    <div class="ol-vehicle-content">
                        <div>
                            <span id="ol-vehicle-content-name">车辆:人车6号</span>|
                            <span id="ol-vehicle-content-person">驾驶员:樊晋刚</span>|
                            <span id="ol-vehicle-content-card">卡号:26910</span>
                            <button class="button button-fill color-primary" id="ol-vehicle-track">追踪</button>
                        </div>
                        <div id="ol-vehicle-pbshow">
                            <div class="item-title item-label">开始时间:
                                <div class="item-input-wrap">
                                    <input type="date" id="ol-stime">
                                </div>
                            </div>|
                            <div class="item-title item-label">结束时间:
                                <div class="item-input-wrap">
                                    <input type="date" id="ol-etime">
                                </div>
                            </div>|
                            <button class="button button-outline color-primary" id="ol-vehicle-playback">轨迹回放</button>
                        </div>
                        <table border="1" class="table">
                            <tr><td>车辆卡号:</td><td id="ol-carcode"></td><td>车辆牌号:</td><td id="ol-carcode2"></td></tr>
                            <tr><td>入井时间:</td><td id="ol-inminetime"></td><td>当前位置:</td><td id="ol-reader"></td></tr>
                            <tr><td>运行速度:</td><td id="ol-speed"></td><td>行使里程:</td><td id="ol-mileage">0km</td></tr>
                            <tr><td>车辆水温:</td><td id="ol-wt">0℃</td><td>甲烷浓度:</td><td id="ol-ch4">0%</td></tr>
                            <tr><td>表面温度:</td><td id="ol-st">0℃</td><td>排气温度:</td><td id="ol-et">0℃</td></tr>
                            <tr><td>车辆转速:</td><td id="ol-rpm">0rpm</td><td>终端电池:</td><td id="ol-battery">0%</td></tr>
                        </table>
                    </div>
                </div>
            `;
            self.$$("#article").append(div);

            const vehicleId = self.utils.getLocalStorage("vehicleId");
            if (vehicleId !== null) {
                self.$$("#ol-vehicle-pbshow").hide();
                self.$$("#ol-vehicle-track").hide();
                self.$$("#ol-vehicle-popup").css("height", "300px");
            }
        }

        htmls();
        popup();
    }

    control() {
        const config = this.algo.getConfig();
        if (config === null) return;

        // 每秒取一个车辆信息
        setInterval(() => {
            this.api.getVehicle().then(resp => {
                if (resp.code === 0) {
                    this.vehicles = resp.data.cars;
                    this.vehicle(this.vehicles);
                    this.draw();
                }
            });
        }, 1000);

        // 从自车的COM口获取数据
        const vehicleId = this.utils.getLocalStorage("vehicleId");
        if (vehicleId !== null && vehicleId !== undefined) {
            this.connect = new Socket("ws://127.0.0.1:8899");
            this.connect.create(async (data) => {
                try {
                    this.selfinfo = JSON.parse(data);
                } catch(err) {
                    console.log("[127.0.0.1:8899]数据解析异常: ", err);
                    this.selfinfo = null;
                }
            });
        }

        this.$$("#ol-vehicle-playback").on("click", async () => {
            this.clear();

            this.drawer.source(Type.Modify).clear();
            const stime = this.$$("#ol-stime").val();
            const etime = this.$$("#ol-etime").val();
            if (stime === "" || etime === "") {
                this.toast("您选择的时间范围存在问题。");
                return;
            }

            const carid = this.$$("#ol-carcode").html();
            const param = { carid: carid, stime: stime, etime: etime };
            const data = await this.api.trackPlayBack(param);
            if (data.length === 0) {
                this.toast("未获取到车辆轨迹数据。");
                return;
            }

            this.$$("#vl-title").html("轨迹回放");
            this.$$("#vl-track-back").show();
            this.$$("#vp-footer").show();

            this.$$("#pannel .page-content").empty();
            this.$$("#pannel").show();
            const div = `<div class="block"><div class="list simple-list"><ul></ul></div></div>`;
            this.$$("#pannel .page-content").append(div);

            this.playbacks = [];
            for (const item of data) {
                const id = `track-${this.utils.uuid()}`;
                const time = item.intime.split('T')[1], time_str = item.intime.replace('T', ' ');
                this.playbacks.push({id: id, rid: parseInt(item.rid), carid: carid, time: time_str});
                let name = item.position;
                if (name.length > 15) { name = item.position.substring(0,18) + "..."; }
                const li = `
                    <li style="font-size: var(--table-row-font-size); cursor: pointer; display: flex; 
                        justify-content: space-between;" id=${id}><span>${name}</span> <span>${time}</span>
                    </li>
                `;
                const color = this.$$("li").css("background-color");

                this.$$("#pannel ul").append(li);
                this.$$(`#${id}`).on("click", () => {
                    _delay('vehicle-playback', async () => {
                        // 正在播放时,不允许进行点击
                        if (this.playbackLocked) {
                            this.toast("正在播放时不允许选择。");
                            return ;
                        }

                        // 首先先恢复所有颜色为默认
                        for (let i = 0; i < this.playbacks.length; i++) {
                            const item = this.playbacks[i];
                            this.$$(`#${item.id}`).css("background-color", color);
                        }

                        // 将选中的列以上的列全都设置为已处理
                        for (let i = 0; i < this.playbacks.length; i++) {
                            const item = this.playbacks[i], position = this.positions.get(item.rid);
                            if (position === undefined) {
                                this.$$(`#${item.id}`).css("background-color", "rgb(255, 255, 0, 0.8)");
                            } else {
                                this.$$(`#${item.id}`).css("background-color", "rgb(0, 255, 0, 0.8)");
                            }
                            if (id === item.id) {
                                // 记录一下开始位置
                                this.playbackIndex = i;
                                break;
                            }
                        }
                    }, 300);
                });
            }
        });

        this.$$("#vl-track-back").on("click", () => {
            this.drawer.source(Type.Modify).clear();
            _delay('vl-track-back', async () => {
                if (this.playbackLocked) {
                    this.$$("#vl-track-back").css("background", "green");
                    this.$$("#vl-track-back").html("开始回放");
                    this.playbackLocked = false;

                    // 关闭估计回放时,如果是车辆追踪模式,需要恢复车辆追踪
                    this.vehicleId = this.utils.getLocalStorage("vehicleId");

                    // 停止播放回放时清空图层
                    this.drawer.source(Type.Modify).clear();
                } else {
                    this.$$("#vl-track-back").css("background", "red");
                    this.$$("#vl-track-back").html("关闭回放");
                    this.playbackLocked = true;

                    // 开启轨迹回放时需要临时关闭车辆追踪
                    this.vehicleId = null;

                    // 播放回放,描画在Modify图层进行
                    await this.playback(this.playbackIndex);

                    // 关闭overlay
                    this.emitter.emit("close-overlay");
                }
            }, 300);
        });

        this.$$("#pannel-close").on("click", () => {
            this.drawer.source(Type.Modify).clear();
            this.$$("#pannel").hide();
            this.clear();
        });

        this.$$("#ol-vehicle-track").on("click", () => {
            this.drawer.source(Type.Modify).clear();
            this.vehicleId = this.$$("#ol-carcode").html();
            this.zoomlocked = true;
        });

        this.$$("#vehicle-locked").on("click", () => {
            this.drawer.source(Type.Modify).clear();
            this.$$("#vl-title").html("车辆列表");
            this.$$("#vl-track-back").hide();
            this.$$("#pannel .page-content").empty();
            if (this.vehicles !== null) {
                const div = `<div class="block"><div class="list simple-list"><ul></ul></div></div>`;
                this.$$("#pannel .page-content").append(div);
                const length = this.vehicles.length;
                for (let i = 0; i < length; i++) {
                    // 如果没有入矿或者分站根本没有匹配,则干脆不显示
                    if (this.vehicles[i].inminetime === null || this.vehicles[i].readerid === null) {
                        continue;
                    }

                    // 如果分站无法匹配，也干脆不显示
                    const postion = this.positions.get(parseInt(this.vehicles[i].readerid));
                    if (postion === undefined) continue;

                    const id = `vehicle--${this.vehicles[i].carcode}--${this.vehicles[i].name}`;
                    const li = `
                        <li style="font-size: var(--table-row-font-size); cursor: pointer;" id=${id}>
                            <span>${this.vehicles[i].carcode} - ${this.vehicles[i].name}</span>
                        </li>
                    `;
                    this.$$("#pannel ul").append(li);
                    this.$$(`#${id}`).on("click", () => {
                        _delay('vehicle-locked', async () => {
                            this.vehicleId = id.split('--')[1];
                            this.zoomlocked = true;
                            this.toast(`${id.split('--')[2]}被锁定。`);
                        }, 300);
                    });
                }
            }
            this.$$("#pannel").show();
            this.toast("点击列表选择需要被锁定的车辆。");
        });

        this.$$("#vehicle-unlocked").on("click", () => {
            this.drawer.source(Type.Modify).clear();
            if (this.vehicleId === null) {
                this.toast("没有车辆被锁定。");
            } else {
                this.vehicleId = null;
                this.toast("车辆锁定解除。");
            }
        });

        this.$$("#vehicle-positions").on("click", () => {
            this.$$("#vl-title").html("分站列表");
            this.$$("#vl-track-back").hide();
            this.$$("#pannel .page-content").empty();
            const div = `<div class="block"><div class="list simple-list"><ul></ul></div></div>`;
            this.$$("#pannel .page-content").append(div);
            for (const position of this.positions.values()) {
                const reader = this.readers.get(position.node_id);
                const id = `positon-${position.node_id}`;
                const li = `
                    <li style="font-size: var(--table-row-font-size); cursor: pointer;" id=${id}>
                        <span>${position.node_id} - ${reader.regname}</span>
                    </li>
                `;
                this.$$("#pannel ul").append(li);
                this.$$(`#${id}`).on("click", () => {
                    _delay('vehicle-positions', async () => {
                        const key = parseInt(id.split('-')[1]);
                        const position = this.positions.get(key);
                        const text = new Text({
                            text: '\ue651',
                            fill: new Fill({ color: 'red' }),
                            font: `normal 30px "iconfont"`
                        });
                        const x = this.algo.normalX(position.x);
                        const y = this.algo.normalY(position.y);
                        const feature = new Feature();
                        feature.setStyle(new Style({ text: text }));
                        feature.setGeometry(new Point([x, y]));
                        this.drawer.source(Type.Modify).addFeature(feature);
                        this.drawer.map.getView().setCenter([x, y]);
                        _timeout(id, () => {
                            this.drawer.source(Type.Modify).removeFeature(feature);
                        }, 5000);
                    }, 300);
                });
            }
            this.$$("#pannel").show();
            this.toast("点击列表选择分站。");
        });

        this.$$("#vehicle-locked-unlocked").on("click", () => {
            if (this.lockedUnlocked) {
                this.$$("#vehicle-locked-unlocked").html("&#xe601;");
                this.vehicleId = false;
                this.lockedUnlocked = false;
            } else {
                this.$$("#vehicle-locked-unlocked").html("&#xe600;");
                this.vehicleId = this.utils.getLocalStorage("vehicleId");
                this.lockedUnlocked = true;
                this.drawer.map.getView().setZoom(12);
            }
        });

        this.$$("#person-slider").on('change', () => {
            let value = this.$$("#person-slider").val();
            value = value === "0" ? 1 : parseInt(value);
            this.playbacklength = 100 * value;
        });
    }
}